package com.thb.pay.manage.comm.aspect;

import com.thb.pay.core.annotation.OperationLog;
import com.thb.pay.core.logs.domain.OperationLogEntity;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

/**
 * @Description 日志切面
 **/
@Slf4j
@Order(1)
@Component
@Aspect
public class OperationLogAspect {

    private static final String LOG_KEY = "logBean";

    //异步处理线程池
    private final static ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);


    public static String getOperationLogValue(ProceedingJoinPoint joinPoint) throws Exception {

        Signature sig = joinPoint.getSignature();
        Method m = joinPoint.getTarget().getClass().getMethod(joinPoint.getSignature().getName(), ((MethodSignature) sig).getParameterTypes());

        OperationLog operationLog = m.getAnnotation(OperationLog.class);
        if (operationLog != null) {
            return operationLog.value();
        }
        return "";
    }

    /**
     * 切点
     */
    @Pointcut("@annotation(com.thb.pay.core.annotation.OperationLog)")
    public void logPointcut() {
    }

    /**
     * 切面
     *
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("logPointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        //包名 方法名
        String methodName = point.getSignature().getName();
        String packageName = point.getThis().getClass().getName();
        if (packageName.indexOf("$$EnhancerByCGLIB$$") > -1 || packageName.indexOf("$$EnhancerBySpringCGLIB$$") > -1) { // 如果是CGLIB动态生成的类
            packageName = packageName.substring(0, packageName.indexOf("$$"));
        }
        final OperationLogEntity operationLog = OperationLogEntity.builder()
                .type(OperationLogEntity.SYSTEM_ADMIN)//运营平台
                .optReqParam(getOperationLogValue(point))//注解备注
                .optReqParam("")//请求参数
                .methodName(packageName + "." + methodName)
                .methodRemark(getOperationLogValue(point))
                .build();

        request.setAttribute(LOG_KEY, operationLog);
        //处理切面任务 发生异常将向外抛出， 不记录日志
        Object result = point.proceed();

        try {
            //TODO 设置账号名称 + 用户
            operationLog.setOptResInfo(result.toString());
            operationLog.setCreateTime(new Date());
            scheduledThreadPool.execute(() -> {
            });
        } catch (Exception e) {
            log.error("OperationLogAspect.error.", e);
        }

        return result;
    }

    @AfterThrowing(value = "logPointcut()", throwing = "ex")
    public void afterThrowing(Throwable ex) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        OperationLogEntity operationLog = (OperationLogEntity) request.getAttribute(LOG_KEY);
        //TODO 操作出现异常

    }
}
